﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

using Swaf;
using Swaf.BizObj;
using Swaf.BizRule;

namespace PageEditing
{
	public class SalPageEditBizRules : Syrinx.BaseBizRules
	{
		protected Regex s_artBlocks = new Regex(@"</?(?:art:|ecom:)(StandAloneArticleListDisplay|StandAloneProductListDisplay)(?:(?:\s+(\w+)(?:\s*=\s*(?:""(.*?)""|'(.*?)'|[^'"">\s]+))?)+\s*|\s*)/?>");
		public IBizObj getPageStandAloneArticleLists(IApplication app, IRuleContext context, string pageName, bool includePageDetails)
		{
			IBizObj salPageInfo = app.bizObjMgr.create("StandAloneArticleListPageInfo");
			IBizObjList sals = (IBizObjList)salPageInfo.get("sals");
			string root = app.resMgr.resolve("$ConfigParam1$");
			string companyShortName = ActiveCompany.get("parentId")==null?"":(string)ActiveCompany.get("shortName");
			string fullPageName = Cmn.pathCombine(root, companyShortName, pageName);
			if (fullPageName.StartsWith("file:\\\\", StringComparison.CurrentCultureIgnoreCase))
				fullPageName = fullPageName.Substring(7);
			FileInfo fi = new FileInfo(fullPageName);
			if (fi.Exists)
			{
				string pageContent = File.ReadAllText(fi.FullName);
				if (includePageDetails)
				{
					salPageInfo.put("pageContent", pageContent);
					salPageInfo.put("pageName", fullPageName);
				}
				populateListFromSals(pageContent, sals);
			}

			return salPageInfo;
		}

		protected void populateListFromSals(string pageContent, IBizObjList sals)
		{
			MatchCollection mc = s_artBlocks.Matches(pageContent);
			IBizObjDefinition bizObjDef = sals.objectType;
			for (int mpos = 0; mpos < mc.Count; mpos++)
			{
				Match m = mc[mpos];
				IBizObj salObj = sals.insertNew();
				for (int pos = 0; pos < m.Groups[2].Captures.Count; pos++)
				{
					string name = m.Groups[2].Captures[pos].Value;
					string val = m.Groups[3].Captures[pos].Value;
					IBizObjField fld = bizObjDef.getField(name, false);
					if (fld != null)
						salObj.put(fld.Name, val);
				}
				salObj.put("componentType", m.Groups[1].Value);
				salObj.put("salHtml", convertSalObjToHtml(salObj));

				if (!m.Groups[0].Value.EndsWith("/>"))
				{
					mpos++;
					int salStartPos = m.Index;
					salObj.put("startPosInPage", salStartPos);
					int startPos = salStartPos + m.Length;
					m = mc[mpos];
					string filterSortCriteria = pageContent.Substring(startPos, m.Index - startPos);
					salObj.put("filterSortCriteria", filterSortCriteria.Trim());
					salObj.put("lengthInPage", m.Index + m.Length - salStartPos);
				}
				else
				{
					salObj.put("startPosInPage", m.Index);
					salObj.put("lengthInPage", m.Length);
				}
			}
		}

		public IBizObj getStandAloneArticleList(IApplication app, IRuleContext context, string pageName, bool dummy, string salId)
		{
			IResults rc = context.RuleGroup.execute(context, "getPageStandAloneArticleLists", pageName, false);
			IBizObj salPageInfo = rc.CallResults as IBizObj;
			if (salPageInfo != null)
			{
				IBizObjList sals = (IBizObjList)salPageInfo.get("sals");
				if (sals != null)
					foreach (IBizObj salObj in sals)
						if (string.Compare((string)salObj.get("id"), salId, true) == 0)
						{
							salObj.put("salHtml", convertSalObjToHtml(salObj));
							return salObj;
						}
			}
			return null;
		}

		public string getSalHtml(IApplication app, IRuleContext context, IBizObj salObj)
		{
			return convertSalObjToHtml(salObj);
		}

		public void updateStandAloneArticleList(IApplication app, IRuleContext context, string pageName, IBizObj updatedSal)
		{
			IResults rc = context.RuleGroup.execute(context, "getPageStandAloneArticleLists", pageName, true);
			IBizObj salPageInfo = rc.CallResults as IBizObj;
			if (salPageInfo != null)
			{
				IBizObjList sals = (IBizObjList)salPageInfo.get("sals");
				if (sals != null)
				{
					string salId = (string)updatedSal.get("id");
					foreach (IBizObj aSalObj in sals)
						if (string.Compare((string)aSalObj.get("id"), salId, true) == 0)
						{
							string origionalPageContent = (string)salPageInfo.get("pageContent");
							StringBuilder newPageContent = new StringBuilder(origionalPageContent.Length + 512);
							int startPos = (int)aSalObj.get("startPosInPage");
							int endPos = (int)aSalObj.get("lengthInPage") + startPos;
							newPageContent.Append(origionalPageContent.Substring(0, startPos));
							newPageContent.Append(convertSalObjToHtml(updatedSal));
							newPageContent.Append(origionalPageContent.Substring(endPos));

							File.WriteAllText((string)salPageInfo.get("pageName"), newPageContent.ToString());
							break;
						}
				}
			}
		}

		public string moveSalsToNewPageLayout(IApplication app, IRuleContext context, object returnValue, object[] inputParams)
		{
			string pageContent = returnValue as string;
			IBizObj pageInfo = inputParams[3] as IBizObj;
			if (pageContent != null && pageInfo != null)
			{
				IResults rc = context.RuleGroup.execute(context, "getPageStandAloneArticleLists", pageInfo.get("pageName"), false);
				IBizObj pageDetails = rc.CallResults as IBizObj;
				if (pageDetails != null)
				{
					Dictionary<string, IBizObj> idMap = new Dictionary<string,IBizObj>();
					List<string> nonMatchedPids = new List<string>();
					IBizObjList origSals = (IBizObjList)pageDetails.get("sals");
					IBizObjList templateSals = app.bizObjMgr.createList("StandAloneArticleList");
					populateListFromSals(pageContent, templateSals);
					foreach (IBizObj tSal in templateSals)
					{
						IBizObj matchSal = origSals.search("id", tSal.get("id"));
						idMap[(string)tSal.get("id")] = matchSal;
					}

					foreach (IBizObj oSal in origSals)
					{
						if (!idMap.ContainsKey((string)oSal.get("id")))
							nonMatchedPids.Add((string)oSal.get("pid"));
					}

					StringBuilder buff = new StringBuilder(pageContent.Length + 1024);
					int lastPos = 0;
					int lastNonMatchPid = 0;
					foreach (IBizObj tSal in templateSals)
					{
						string newPid = null;
						IBizObj origMatch = idMap[(string)tSal.get("id")];
						if (origMatch != null)
							newPid = (string)origMatch.get("pid");
						else if(lastNonMatchPid < nonMatchedPids.Count)
							newPid = nonMatchedPids[lastNonMatchPid++];
						int index = (int)tSal.get("startPosInPage");
						int len = (int)tSal.get("lengthInPage");
						buff.Append(pageContent.Substring(lastPos, index-lastPos));
						if(newPid != null)
							tSal.put("pid", newPid);
						buff.Append(convertSalObjToHtml(tSal));
						lastPos = index + len;
					}
					buff.Append(pageContent.Substring(lastPos));
					if (lastNonMatchPid < nonMatchedPids.Count)
					{
						buff.Append("<%-- User defined controls not used in page template:\n");
						for (int pos = lastNonMatchPid; pos < nonMatchedPids.Count; pos++)
						{
							if (nonMatchedPids[pos] != null)
							{
								IBizObj orig = origSals.search("pid", nonMatchedPids[pos]);
								buff.Append(convertSalObjToHtml(orig)).Append("\n");
							}
						}
						buff.Append("-----------------------------------------------------%>\n");
					}
					pageContent = buff.ToString();
				}
			}

			return pageContent;
		}

		public string getSalEditorType(IApplication app, IRuleContext context, IBizObj bizobj, Swaf.Security.Privileges editPriv
				, string parentBPIds, string pageName)
		{
			string temp = "";
			if (bizobj != null && !Cmn.IsEmpty(bizobj.get("componentType")))
			{
				KnownComponentTypes ct = (KnownComponentTypes)Enum.Parse(typeof(KnownComponentTypes), (string)bizobj.get("componentType"));
				switch (ct)
				{
					case KnownComponentTypes.StandAloneArticleListDisplay:
						temp = "PageEditing.Gui.AspNet.BasicSalOptionsRWDisplay";
						break;
					case KnownComponentTypes.StandAloneProductListDisplay:
						temp = "PageEditing.Gui.AspNet.BasicSplOptionsRWDisplay";
						break;
				}
			}
			return temp;
		}

		protected enum KnownComponentTypes { StandAloneArticleListDisplay, StandAloneProductListDisplay };
		protected internal static string convertSalObjToHtml(IBizObj salObj)
		{
			StringBuilder buff = new StringBuilder(512);
			KnownComponentTypes ct = (KnownComponentTypes)Enum.Parse(typeof(KnownComponentTypes), (string)salObj.get("componentType"));
			switch (ct)
			{
				case KnownComponentTypes.StandAloneArticleListDisplay:
					buff.Append("<art:StandAloneArticleListDisplay runat=\"server\" ");
					break;
				case KnownComponentTypes.StandAloneProductListDisplay:
					buff.Append("<ecom:StandAloneProductListDisplay runat=\"server\" ");
					break;
			}
			foreach (IBizObjField fld in salObj.type.OrderedFields)
			{
				if (fld.Name.CompareTo("ESF") == 0)
					break;
				string fieldVal = (string)salObj.get(fld.Name);
				if (fieldVal != null)
					buff.AppendFormat("{0}=\"{1}\" ", fld.Name, fieldVal);
			}
			string filterSortCriteria = (string)salObj.get("filtersortCriteria");
			if (filterSortCriteria == null)
				buff.Append("/>");
			else
			{
				buff.Append(">\n").Append(filterSortCriteria);
				switch(ct)
				{
					case KnownComponentTypes.StandAloneArticleListDisplay:
						buff.Append("\n</art:StandAloneArticleListDisplay>");
						break;
					case KnownComponentTypes.StandAloneProductListDisplay:
						buff.Append("\n</ecom:StandAloneProductListDisplay>");
						break;
				}
			}
			return buff.ToString();
		}

		protected static string s_artTemplateKey = "Articles.Gui.AspNet.ArticleListDisplay-";
		public IBizObjList getAvailableSalTemplates(IApplication app, IRuleContext context)
		{
			IBizObjList templates = app.bizObjMgr.createList("SalTemplate");
			string assemblyName = app.resMgr.resolve(Cmn.pathCombine(app.resMgr.getMacro("BaseBinLocation"), "Articles.Gui.AspNet.dll"));
			if (assemblyName.StartsWith("file:\\\\", StringComparison.CurrentCultureIgnoreCase))
				assemblyName = assemblyName.Substring(7);
			Assembly artAss = Assembly.LoadFrom(assemblyName);
			if (artAss != null)
			{
				string[] resources = artAss.GetManifestResourceNames();
				foreach (string rez in resources)
				{
					if (rez.StartsWith(s_artTemplateKey))
					{
						IBizObj template = templates.insertNew();
						string shortName = rez.Substring(s_artTemplateKey.Length);
						if (shortName.EndsWith(".ascx"))
							shortName = shortName.Substring(0, shortName.Length - 5);
						template.put("name", shortName);
						template.put("fullName", rez);
					}
				}
			}
			return templates.getIndex("name");
		}

		protected static string s_prodTemplateKey = "eCom.Gui.AspNet.SOItemsListDisplay-";
		public IBizObjList getAvailableSplTemplates(IApplication app, IRuleContext context)
		{
			IBizObjList templates = app.bizObjMgr.createList("SalTemplate");
			string assemblyName = app.resMgr.resolve(Cmn.pathCombine(app.resMgr.getMacro("BaseBinLocation"), "eCom.Gui.AspNet.dll"));
			if (assemblyName.StartsWith("file:\\\\", StringComparison.CurrentCultureIgnoreCase))
				assemblyName = assemblyName.Substring(7);
			Assembly artAss = Assembly.LoadFrom(assemblyName);
			if (artAss != null)
			{
				string[] resources = artAss.GetManifestResourceNames();
				foreach (string rez in resources)
				{
					if (rez.StartsWith(s_prodTemplateKey))
					{
						IBizObj template = templates.insertNew();
						string shortName = rez.Substring(s_prodTemplateKey.Length);
						if (shortName.EndsWith(".ascx"))
							shortName = shortName.Substring(0, shortName.Length - 5);
						template.put("name", shortName);
						template.put("fullName", rez);
					}
				}
			}
			return templates.getIndex("name");
		}
	}
}
